package cn.tedu.lucky.draw.server.service.impl;

import cn.tedu.lucky.draw.server.common.enums.DrawEnum;
import cn.tedu.lucky.draw.server.common.enums.ErrorEnum;
import cn.tedu.lucky.draw.server.common.handler.DrawException;
import cn.tedu.lucky.draw.server.protocol.po.Activity;
import cn.tedu.lucky.draw.server.protocol.po.ActivityResult;
import cn.tedu.lucky.draw.server.protocol.po.Prize;
import cn.tedu.lucky.draw.server.protocol.po.Rule;
import cn.tedu.lucky.draw.server.protocol.query.ActivityQuery;
import cn.tedu.lucky.draw.server.repository.ActivityRepository;
import cn.tedu.lucky.draw.server.repository.ActivityResultRepository;
import cn.tedu.lucky.draw.server.service.IActivityRuleService;
import cn.tedu.lucky.draw.server.service.IActivityService;
import cn.tedu.lucky.draw.server.service.IPrizeService;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务层-抽奖活动接口实现类
 */
@Slf4j
@Service
public class ActivityService implements IActivityService {
    @Autowired
    private ActivityRepository activityRepository;

    @Autowired
    private IActivityRuleService activityRuleService;

    @Autowired
    private ActivityResultRepository activityResultRepository;

    @Autowired
    private IPrizeService prizeService;

    List<Activity> activityList;

    @Override
    public void saveActivity(Activity activity) {
        log.debug("Service-新增抽奖活动-activity:{}",activity);
        activity.setStatus(0);
        activity.setCreateTime(LocalDateTime.now());
        activity.setUpdateTime(LocalDateTime.now());
        Activity activity1 = activityRepository.save(activity);

        activityList = null;

        if (activity1 == null)
            throw new DrawException(ErrorEnum.SYSTEM_ERROR);
    }

    @Override
    public List<Activity> getAll(ActivityQuery activityQuery) {
        if (activityList == null){
            activityList = activityRepository.findAll();
        }

        String name = activityQuery.getName();
        Integer status = activityQuery.getStatus();

        return activityList.stream()
                .filter(activity -> (name == null || name == "" || name.equals(activity.getName())))
                .filter(activity -> (status == null || status.equals(activity.getStatus())))
                .collect(Collectors.toList());
    }

    @Override
    public Activity findActivityById(Long id) {
        Optional<Activity> activityOptional = activityRepository.findById(id);
        Activity activity = null;
        if (activityOptional.isPresent()) {
            activity = activityOptional.get();
        }
        return activity;
    }

    @Override
    public List<Activity> findAll() {
        Integer status = Integer.valueOf(DrawEnum.ENABLE.getCode());
        return activityRepository.findByStatusEquals(status);
    }

    @Override
    public Prize trigger(Long activityId) throws JSONException {
        //1. 获取活动规则
        List<Rule> ruleList = activityRuleService.findRuleByActivityId(activityId);
        //2. 校验用户资格
        //2.1 检测剩余抽奖次数
        boolean value = false;
        for (Rule rule : ruleList) {
            //type=1,表示改规则用于限制抽奖次数
            if (rule.getType() == 1){
                JSONObject jsonObject = new JSONObject(rule.getContent());
                int count = jsonObject.getInt("count");
                Integer result = activityResultRepository
                        .countActivityResultsByActivityIdAndUserId(activityId, 999L);
                if (result >= count){
                    //2.2 提示抽奖此时用尽
                    throw new DrawException(ErrorEnum.DRAW_COUNT_RUNOUT);
                }
            } else {
                //2.3 检测中奖概率
                JSONObject jsonObject = new JSONObject(rule.getContent());
                value = jsonObject.getBoolean("value");
            }
        }
        //获取奖品列表
        List<Prize> prizes = prizeService.findPrizeByActivityId(activityId);


        //3. 分配抽奖概率
        Map<Prize, Double> prizeProbabilityMap = new HashMap();
        double totalInverseValue = prizes.stream().mapToDouble(prize -> 1.0 / prize.getValue()).sum();

        //4. 如果需要降低概率，则所有概率值乘以一个小于1的因子
        double decreaseFactor = value ? 0.5 : 1.0;
        for (Prize prize : prizes) {
            double individualProbability = (1.0 / prize.getValue()) / totalInverseValue;
            prizeProbabilityMap.put(prize, individualProbability * decreaseFactor);
        }

        //5. 执行抽奖
        double randomValue = new Random().nextDouble();
        double cumulativeProbability = 0.0;
        for (Map.Entry<Prize, Double> entry : prizeProbabilityMap.entrySet()) {
            Prize prize = entry.getKey();
            Double probability = entry.getValue();

            cumulativeProbability += probability;
            //中奖了
            if (randomValue <= cumulativeProbability) {
                prize.setStock(prize.getStock()-1);
                prizeService.save(prize);//更新奖品库存
                saveActivityResult(activityId,prize.getId());//记录中奖信息
                return prize; // 返回中奖的奖品对象
            }
        }
        //5. 进行抽奖
        Prize prize = new Prize();
        prize.setName("谢谢参与");
        prize.setImg("图片路径");
        prize.setId(99999999L);
        //6. 记录中奖信息
        saveActivityResult(activityId,prize.getId());
        return prize;
    }

    private void saveActivityResult(Long activityId, Long prizeId) {
        ActivityResult activityResult = new ActivityResult();
        activityResult.setActivityId(activityId);
        activityResult.setUserId(999L);
        activityResult.setPrizeId(prizeId);
        activityResult.setWinTime(LocalDateTime.now());
        activityResult.setStatus(0);
        activityResultRepository.save(activityResult);
    }

}
